home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1996 / MacHack 1996.toast / Hacks / Hacks ’91 / AliasThis! / AliasThisƒ / src / SampleMain.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-20  |  24.7 KB  |  899 lines  |  [TEXT/MPS ]

  1. #include "Sample.h"        /* bring in all the #defines for Sample */
  2. #include "SampleDefs.h"
  3. #include "SampleAEvt.h"
  4. #include "SampleFileIO.h"
  5. #include "SamplePrint.h"
  6. #include "SampleErrors.h"
  7. #include "SampleMain.h"
  8.  
  9. #include <Resources.h>
  10. #include <Fonts.h>
  11. #include <Windows.h>
  12. #include <Menus.h>
  13. #include <Desk.h>
  14. #include <ToolUtils.h>
  15. #include <Memory.h>
  16. #include <OSEvents.h>
  17. #include <DiskInit.h>
  18. #include <Traps.h>
  19. #include <Errors.h>
  20.  
  21. SysEnvRec    gMac;                        /* set up by Initialize */
  22. Boolean        gHasWaitNextEvent;            /* set up by Initialize */
  23. Boolean        gInBackground = false;        /* maintained by DoEvent */
  24. Rect        gStopRect;                    /* set up by Initialize */
  25. Rect        gGoRect;                    /* set up by Initialize */
  26. THPrint        gPrRecHdl;
  27. Str255        gTitle;
  28. Boolean        gQuit = false;
  29. Boolean        gHasPPCToolbox = false;
  30. Boolean        gHasAppleEvents = false;
  31. Boolean        gSendToSelf = true;
  32. Boolean        gHasNewStdFile = false;
  33. WindowData    gWindowData;
  34. short        gReplyMode = kAENoReply;
  35. RgnHandle    gCursorRgn;
  36.  
  37. Boolean                gDefaultOK = false;
  38. LocationNameRec        gLocation;
  39. PortInfoRec            gPortInfo;
  40.  
  41.  
  42. /* Define HiWrd and LoWrd macros for efficiency. */
  43. #define HiWrd(aLong)    (((aLong) >> 16) & 0xFFFF)
  44. #define LoWrd(aLong)    ((aLong) & 0xFFFF)
  45.  
  46. /* Define TopLeft and BotRight macros for convenience. Notice the implicit
  47.    dependency on the ordering of fields within a Rect */
  48. #define TopLeft(aRect)    (* (Point *) &(aRect).top)
  49. #define BotRight(aRect)    (* (Point *) &(aRect).bottom)
  50.  
  51.  
  52. /* This routine is part of the MPW runtime library. This external
  53.    reference to it is done so that we can unload its segment, %A5Init. */
  54.  
  55. extern void _DataInit();
  56.  
  57.  
  58. #pragma segment Main
  59. main()
  60. {
  61.     MaxApplZone();
  62.     Initialize();                    /* initialize the program */
  63. //    StartDocuments();                /* open any documents if requested */
  64.  
  65.     EventLoop();                    /* call the main event loop */
  66. }
  67.  
  68.  
  69. /*    Get events forever, and handle them by calling DoEvent.
  70.     Get the events by calling WaitNextEvent, if it's available, otherwise
  71.     by calling GetNextEvent. Also call AdjustCursor each time through the loop. */
  72.  
  73. #pragma segment Main
  74. void EventLoop()
  75. {
  76.     Boolean        gotEvent;
  77.     EventRecord    event;
  78.     Point        mouse;
  79.  
  80.     gCursorRgn = NewRgn();            /* we’ll pass WNE an empty region the 1st time thru */
  81.     do {
  82.         /* use WNE if it is available */
  83.         if ( gHasWaitNextEvent ) {
  84.             GetGlobalMouse(&mouse);
  85.             /* AdjustCursor(mouse, gCursorRgn, (event.what == kHighLevelEvent)); */
  86.             /* needed to remove MaxLong as the sleep value so help manager would get
  87.                 time to display balloons over the traffic light window
  88.             */
  89.             gotEvent = WaitNextEvent(everyEvent, &event, 30, gCursorRgn);
  90.         }
  91.         else {
  92.             SystemTask();
  93.             gotEvent = GetNextEvent(everyEvent, &event);
  94.         }
  95.         AdjustCursor(event.where, gCursorRgn, (event.what == kHighLevelEvent), *(long *) &event.where);
  96.         if ( gotEvent ) {
  97.             DoEvent(&event);
  98.         }
  99.         /*    If you are using modeless dialogs that have editText items,
  100.             you will want to call IsDialogEvent to give the caret a chance
  101.             to blink, even if WNE/GNE returned FALSE. However, check FrontWindow
  102.             for a non-NIL value before calling IsDialogEvent. */
  103.     } while ( !gQuit );
  104. } /*EventLoop*/
  105.  
  106.  
  107. /* Do the right thing for an event. Determine what kind of event it is, and call
  108.  the appropriate routines. */
  109.  
  110. #pragma segment Main
  111. void DoEvent( EventRecord *event )
  112. {
  113.     short        part, err;
  114.     WindowPtr    window;
  115.     char        key;
  116.     Point        aPoint;
  117.  
  118.     switch ( event->what ) {
  119.         case mouseDown:
  120.             part = FindWindow(event->where, &window);
  121.             switch ( part ) {
  122.                 case inMenuBar:                /* process a mouse menu command (if any) */
  123.                     AdjustMenus();
  124.                     DoMenuCommand(MenuSelect(event->where));
  125.                     break;
  126.             }
  127.             break;
  128.         case keyDown:
  129.         case autoKey:                        /* check for menukey equivalents */
  130.             key = event->message & charCodeMask;
  131.             if ( event->modifiers & cmdKey )            /* Command key down */
  132.                 if ( event->what == keyDown ) {
  133.                     AdjustMenus();                        /* enable/disable/check menu items properly */
  134.                     DoMenuCommand(MenuKey(key));
  135.                 }
  136.             break;
  137.         case activateEvt:
  138.             DoActivate((WindowPtr) event->message, (event->modifiers & activeFlag) != 0);
  139.             break;
  140.         case updateEvt:
  141.             DoUpdate((WindowPtr) event->message);
  142.             break;
  143.         /*    1.01 - It is not a bad idea to at least call DIBadMount in response
  144.             to a diskEvt, so that the user can format a floppy. */
  145.         case diskEvt:
  146.             if ( HiWrd(event->message) != noErr ) {
  147.                 SetPt(&aPoint, kDILeft, kDITop);
  148.                 err = DIBadMount(aPoint, event->message);
  149.             }
  150.             break;
  151.         case kOSEvent:
  152.         /*    1.02 - must BitAND with 0x0FF to get only low byte */
  153.             switch ((event->message >> 24) & 0x0FF) {        /* high byte of message */
  154.                 case kSuspendResumeMessage:        /* suspend/resume is also an activate/deactivate */
  155.                     gInBackground = (event->message & kResumeMask) == 0;
  156.                     DoActivate(FrontWindow(), !gInBackground);
  157.                     break;
  158.  
  159.                 default:
  160.                     break;
  161.             }
  162.             break;
  163.  
  164.         case kHighLevelEvent:
  165.             DoHighLevelEvent(event);
  166.             break;
  167.     }
  168. } /*DoEvent*/
  169.  
  170.  
  171. /*    Change the cursor's shape, depending on its position. This also calculates
  172.     the region where the current cursor resides (for WaitNextEvent). If the
  173.     mouse is ever outside of that region, an event would be generated, causing
  174.     this routine to be called, allowing us to change the region to the region
  175.     the mouse is currently in. If there is more to the event than just “the
  176.     mouse moved”, we get called before the event is processed to make sure the
  177.     cursor is the right one. In any (ahem) event, this is called again before
  178.     we fall back into WNE.
  179.     
  180.     Take special care on a kHighLevelEvent. Remember, event.where holds the
  181.     class ID, not a mouse position!
  182. */
  183.  
  184. #pragma segment Main
  185. void AdjustCursor( Point mouse, RgnHandle region, Boolean isAppleEvent, long classID )
  186. {
  187.     WindowPtr    window;
  188.     RgnHandle    arrowRgn;
  189.     RgnHandle    plusRgn;
  190.     Rect        globalPortRect;
  191.     short        cursorID;
  192.  
  193.     window = FrontWindow();    /* we only adjust the cursor when we are in front */
  194.     if ( (! gInBackground) && (! IsDAWindow(window)) ) {
  195.         if (isAppleEvent) {
  196.             switch (classID) {
  197.                 case kAEOpenApplication:        cursorID = oappCursor; break;
  198.                 case kAEOpenDocuments:            cursorID = odocCursor; break;
  199.                 case kAEPrintDocuments:            cursorID = pdocCursor; break;
  200.                 case kAEQuitApplication:        cursorID = quitCursor; break;
  201.                 case kAEAnswer:                    cursorID = ansrCursor; break;
  202.                 case traeMoveFrontWindowMsgID:    cursorID = mvfwCursor; break;
  203.                 case traeEchoID:                cursorID = echoCursor; break;
  204.                 case 'wait':                    cursorID = watchCursor; break;
  205.             }
  206.             SetCursor(*GetCursor(cursorID));
  207.             SetRectRgn(region, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos);
  208.         }
  209.         else {
  210.             /* calculate regions for different cursor shapes */
  211.             arrowRgn = NewRgn();
  212.             plusRgn = NewRgn();
  213.     
  214.             /* start with a big, big rectangular region */
  215.             SetRectRgn(arrowRgn, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos);
  216.     
  217.             /* calculate plusRgn */
  218.             if ( IsAppWindow(window) ) {
  219.                 SetPort(window);    /* make a global version of the viewRect */
  220.                 SetOrigin(-window->portBits.bounds.left, -window->portBits.bounds.top);
  221.                 globalPortRect = window->portRect;
  222.                 RectRgn(plusRgn, &globalPortRect);
  223.                 SectRgn(plusRgn, window->visRgn, plusRgn);
  224.                 SetOrigin(0, 0);
  225.             }
  226.     
  227.             /* subtract other regions from arrowRgn */
  228.             DiffRgn(arrowRgn, plusRgn, arrowRgn);
  229.     
  230.             /* change the cursor and the region parameter */
  231.             if ( PtInRgn(mouse, plusRgn) ) {
  232.                 SetCursor(*GetCursor(plusCursor));
  233.                 CopyRgn(plusRgn, region);
  234.             } else {
  235.                 SetCursor(&qd.arrow);
  236.                 CopyRgn(arrowRgn, region);
  237.             }
  238.     
  239.             /* get rid of our local regions */
  240.             DisposeRgn(arrowRgn);
  241.             DisposeRgn(plusRgn);
  242.         }
  243.     }
  244. } /*AdjustCursor*/
  245.  
  246.  
  247. /*    Get the global coordinates of the mouse. When you call OSEventAvail
  248.     it will return either a pending event or a null event. In either case,
  249.     the where field of the event record will contain the current position
  250.     of the mouse in global coordinates and the modifiers field will reflect
  251.     the current state of the modifiers. Another way to get the global
  252.     coordinates is to call GetMouse and LocalToGlobal, but that requires
  253.     being sure that thePort is set to a valid port. */
  254.  
  255. #pragma segment Main
  256. void GetGlobalMouse( Point *mouse )
  257. {
  258.     EventRecord    event;
  259.  
  260.     OSEventAvail(kNoEvents, &event);    /* we aren't interested in any events */
  261.     *mouse = event.where;                /* just the mouse position */
  262. } /*GetGlobalMouse*/
  263.  
  264.  
  265. /*    This is called when an update event is received for a window.
  266.     It calls DrawWindow to draw the contents of an application window.
  267.     As an effeciency measure that does not have to be followed, it
  268.     calls the drawing routine only if the visRgn is non-empty. This
  269.     will handle situations where calculations for drawing or drawing
  270.     itself is very time-consuming. */
  271.  
  272. #pragma segment Main
  273. void DoUpdate( WindowPtr window )
  274. {
  275.     if ( IsAppWindow(window) ) {
  276.         BeginUpdate(window);                /* this sets up the visRgn */
  277.         if ( ! EmptyRgn(window->visRgn) ) {    /* draw if updating needs to be done */
  278.             SetPort(window);
  279.             EraseRect(&window->portRect);
  280.             DrawWindow(window);
  281.         }
  282.         EndUpdate(window);
  283.     }
  284. } /*DoUpdate*/
  285.  
  286.  
  287. /*    This is called when a window is activated or deactivated.
  288.     In Sample, the Window Manager's handling of activate and
  289.     deactivate events is sufficient. Other applications may have
  290.     TextEdit records, controls, lists, etc., to activate/deactivate. */
  291.  
  292. #pragma segment Main
  293. void DoActivate( WindowPtr window, Boolean becomingActive )
  294. {
  295.     if ( IsAppWindow(window) ) {
  296.         if ( becomingActive )
  297.             /* do whatever you need to at activation */ ;
  298.         else
  299.             /* do whatever you need to at deactivation */ ;
  300.     }
  301. } /*DoActivate*/
  302.  
  303.  
  304. /*    This is called when a mouse-down event occurs in the content of a window.
  305.     Other applications might want to call FindControl, TEClick, etc., to
  306.     further process the click. */
  307.  
  308. #pragma segment Main
  309. void DoContentClick( WindowPtr window )
  310. {
  311.     SetLight(window, ! GetLight(window));
  312. } /*DoContentClick*/
  313.  
  314.  
  315. /* Draw the contents of the application window. We do some drawing in color, using
  316.    Classic QuickDraw's color capabilities. This will be black and white on old
  317.    machines, but color on color machines. At this point, the window’s visRgn
  318.    is set to allow drawing only where it needs to be done. */
  319.  
  320. #pragma segment Main
  321. void DrawWindow( GrafPtr window )
  322. {
  323.     if ( GetLight(window) ) {                    /* draw a red (or white) stop light */
  324.         ForeColor(redColor);
  325.         PaintOval(&gStopRect);
  326.     }
  327.     ForeColor(blackColor);
  328.     FrameOval(&gStopRect);
  329.  
  330.     if ( ! GetLight(window) ) {                /* draw a green (or white) go light */
  331.         ForeColor(greenColor);
  332.         PaintOval(&gGoRect);
  333.     }
  334.     ForeColor(blackColor);
  335.     FrameOval(&gGoRect);
  336.  
  337. } /*DrawWindow*/
  338.  
  339.  
  340. /*    Enable and disable menus based on the current state.
  341.     The user can only select enabled menu items. We set up all the menu items
  342.     before calling MenuSelect or MenuKey, since these are the only times that
  343.     a menu item can be selected. Note that MenuSelect is also the only time
  344.     the user will see menu items. This approach to deciding what enable/
  345.     disable state a menu item has the advantage of concentrating all
  346.     the decision-making in one routine, as opposed to being spread throughout
  347.     the application. Other application designs may take a different approach
  348.     that is just as valid. */
  349.  
  350. #pragma segment Main
  351. void AdjustMenus()
  352. {
  353.     WindowPtr    window;
  354.     MenuHandle    menu;
  355.  
  356.     window = FrontWindow();
  357.  
  358.     menu = GetMHandle(mFile);
  359.  
  360.     EnableItem(menu, iNew);
  361.     EnableItem(menu, iOpen);
  362.     if ( !window ) {
  363.         DisableItem(menu, iClose);
  364.         DisableItem(menu, iSave);
  365.         DisableItem(menu, iSaveAs);
  366.         DisableItem(menu, iRevert);
  367.         DisableItem(menu, iPageSetup);
  368.         DisableItem(menu, iPrint);
  369.     }
  370.     else if ( IsDAWindow(window) ) {        /* we can allow desk accessories to be closed from the menu */
  371.         DisableItem(menu, iNew);
  372.         DisableItem(menu, iOpen);
  373.         DisableItem(menu, iSave);
  374.         DisableItem(menu, iSaveAs);
  375.         DisableItem(menu, iRevert);
  376.         DisableItem(menu, iPageSetup);
  377.         DisableItem(menu, iPrint);
  378.         EnableItem(menu, iClose);
  379.     }
  380.     else {
  381.         EnableItem(menu, iPageSetup);
  382.         EnableItem(menu, iPrint);
  383.         EnableItem(menu,iSave);
  384.         EnableItem(menu, iClose);    /* but not our traffic light window */
  385.     }
  386.  
  387.     menu = GetMHandle(mEdit);
  388.     if ( IsDAWindow(window) ) {        /* a desk accessory might need the edit menu… */
  389.         EnableItem(menu, iUndo);
  390.         EnableItem(menu, iCut);
  391.         EnableItem(menu, iCopy);
  392.         EnableItem(menu, iClear);
  393.         EnableItem(menu, iPaste);
  394.     } else {                        /* …but we don’t use it */
  395.         DisableItem(menu, iUndo);
  396.         DisableItem(menu, iCut);
  397.         DisableItem(menu, iCopy);
  398.         DisableItem(menu, iClear);
  399.         DisableItem(menu, iPaste);
  400.     }
  401.  
  402.     menu = GetMHandle(mLight);
  403.     if ( IsAppWindow(window) ) {    /* we know that it must be the traffic light */
  404.         EnableItem(menu, iStop);
  405.         EnableItem(menu, iGo);
  406.         if (window) {
  407.             CheckItem(menu, iStop, GetLight(window)); /* we can also determine check/uncheck state, too */
  408.             CheckItem(menu, iGo, !GetLight(window));
  409.         } else {
  410.             CheckItem(menu, iStop, false);
  411.             CheckItem(menu, iGo, false);
  412.         }
  413.     } else {
  414.         DisableItem(menu, iStop);
  415.         DisableItem(menu, iGo);
  416.     }
  417.  
  418.     menu = GetMHandle(mSendEvent);
  419.     if (!gHasAppleEvents)
  420.         DisableItem(menu, 0);
  421.     else {
  422.         EnableItem(menu, 0);
  423.         if (!gHasPPCToolbox)
  424.             DisableItem(menu, iChooseTarget);
  425.         else {
  426.             EnableItem(menu, iChooseTarget);
  427.             CheckItem(menu, iChooseTarget, gSendToSelf);
  428.         }
  429.         DisableItem(menu, iSendClose);
  430.         if (window)
  431.             EnableItem(menu, iSendMove);
  432.         else
  433.             DisableItem(menu, iSendMove);
  434.         EnableItem(menu, iSpeedTest);
  435.         EnableItem(menu, iUseNoReply);
  436.         EnableItem(menu, iUseWaitReply);
  437.         EnableItem(menu, iUseQueueReply);
  438.         CheckItem(menu, iUseNoReply, gReplyMode == kAENoReply);
  439.         CheckItem(menu, iUseWaitReply, gReplyMode == kAEWaitReply);
  440.         CheckItem(menu, iUseQueueReply, gReplyMode == kAEQueueReply);
  441.     }
  442. } /*AdjustMenus*/
  443.  
  444.  
  445. /*    This is called when an item is chosen from the menu bar (after calling
  446.     MenuSelect or MenuKey). It performs the right operation for each command.
  447.     It is good to have both the result of MenuSelect and MenuKey go to
  448.     one routine like this to keep everything organized. */
  449.  
  450. #pragma segment Main
  451. void DoMenuCommand( long menuResult )
  452. {
  453.     short        menuID;                /* the resource ID of the selected menu */
  454.     short        menuItem;            /* the item number of the selected menu */
  455.     short        itemHit;
  456.     Str255        daName;
  457.     short        daRefNum;
  458.     Boolean        handledByDA;
  459.     WindowPtr    window;
  460.     OSErr        err;
  461.  
  462.     window = FrontWindow();
  463.     menuID = HiWrd(menuResult);    /* use macros for efficiency to... */
  464.     menuItem = LoWrd(menuResult);    /* get menu item number and menu number */
  465.     switch ( menuID ) {
  466.         case mApple:
  467.             switch ( menuItem ) {
  468.                 case iAbout:        /* bring up alert for About */
  469.                     itemHit = Alert(rAboutAlert, nil);
  470.                     break;
  471.                 default:            /* all non-About items in this menu are DAs */
  472.                     GetItem(GetMHandle(mApple), menuItem, daName);
  473.                     daRefNum = OpenDeskAcc(daName);
  474.                     break;
  475.             }
  476.             break;
  477.         case mFile:
  478.             switch ( menuItem ) {
  479.                 case iNew:
  480.                     err = OpenNewWindow();
  481.                     break;
  482.                 case iOpen:
  483.                     err = OpenFile(nil);
  484.                     break;
  485.                 case iSave:
  486.                     if ( window && SaveFile(window) ) {};
  487.                     break;
  488.                 case iClose:
  489.                     DoCloseWindow(window);
  490.                     break;
  491.                 case iPageSetup:
  492.                     PresentStyleDialog();
  493.                     break;
  494.                 case iPrint:
  495.                     err = StartPrintingProcess(true, &(window->portRect));
  496.                     break;
  497.                 case iQuit:
  498.                     Terminate();
  499.                     break;
  500.             }
  501.             break;
  502.         case mEdit:                    /* call SystemEdit for DA editing & MultiFinder */
  503.             handledByDA = SystemEdit(menuItem-1);    /* since we don’t do any Editing */
  504.             break;
  505.         case mLight:
  506.             switch ( menuItem ) {
  507.                 case iStop:
  508.                     SetLight(window, true);
  509.                     break;
  510.                 case iGo:
  511.                     SetLight(window, false);
  512.                     break;
  513.             }
  514.             break;
  515.         case mSendEvent:
  516.             switch ( menuItem ) {
  517.                 case iChooseTarget:
  518.                     gSendToSelf = !gSendToSelf;
  519.                     break;
  520.                 case iSendClose:
  521.                     break;
  522.                 case iSendMove:
  523.                     CreateAndSendAppleEvent(traeMoveFrontWindowMsgID);
  524.                     break;
  525.                 case iSpeedTest:
  526.                     CreateAndSendAppleEvent(traeEchoID);
  527.                     break;
  528.                 case iUseNoReply:
  529.                     gReplyMode = kAENoReply;
  530.                     break;
  531.                 case iUseWaitReply:
  532.                     gReplyMode = kAEWaitReply;
  533.                     break;
  534.                 case iUseQueueReply:
  535.                     gReplyMode = kAEQueueReply;
  536.                     break;
  537.             }
  538.     }
  539.     HiliteMenu(0);                    /* unhighlight what MenuSelect (or MenuKey) hilited */
  540. } /*DoMenuCommand*/
  541.  
  542.  
  543. /* Change the setting of the light. */
  544.  
  545. #pragma segment Main
  546. void SetLight( WindowPtr window, Boolean newStopped )
  547. {
  548.     WindowDataHandle wData;
  549.  
  550.     if ( newStopped != GetLight(window) ) {
  551.         wData = (WindowDataHandle) ((WindowPeek) window)->refCon;
  552.         (**wData).stopped = newStopped;
  553.         SetPort(window);
  554.         InvalRect(&window->portRect);
  555.     }
  556. } /*SetLight*/
  557.  
  558.  
  559. /* Return the setting of the light. */
  560.  
  561. #pragma segment Main
  562. Boolean GetLight( WindowPtr window )
  563. {
  564.     WindowDataHandle wData;
  565.  
  566.     if (window) {
  567.         wData = (WindowDataHandle) ((WindowPeek) window)->refCon;
  568.         return((**wData).stopped);
  569.     }
  570.     else
  571.         return(false);
  572.  
  573. } /*GetLight*/
  574.  
  575.  
  576. /* Close a window. This handles desk accessory and application windows. */
  577.  
  578. /*    1.01 - At this point, if there was a document associated with a
  579.     window, you could do any document saving processing if it is 'dirty'.
  580.     DoCloseWindow would return true if the window actually closed, i.e.,
  581.     the user didn’t cancel from a save dialog. This result is handy when
  582.     the user quits an application, but then cancels the save of a document
  583.     associated with a window. */
  584.  
  585. #pragma segment Main
  586. Boolean DoCloseWindow( WindowPtr window )
  587. {
  588.  
  589.     if ( IsDAWindow(window) )
  590.         CloseDeskAcc(((WindowPeek) window)->windowKind);
  591.     else if ( IsAppWindow(window) ) {
  592.         DisposHandle((Handle) ((WindowPeek) window)->refCon);
  593.         DisposeWindow(window);
  594.     }
  595.  
  596.     return true;
  597. } /*DoCloseWindow*/
  598.  
  599.  
  600. /* Clean up the application and exit. We close all of the windows so that
  601.  they can update their documents, if any. */
  602.  
  603. /*    1.01 - If we find out that a cancel has occurred, we won't exit to the
  604.     shell, but will return instead. */
  605.  
  606. #pragma segment Main
  607. void Terminate()
  608. {
  609.     WindowPtr    aWindow;
  610.     Boolean        closed;
  611.  
  612.     closed = true;
  613.     do {
  614.         aWindow = FrontWindow();                /* get the current front window */
  615.         if (aWindow != nil)
  616.             closed = DoCloseWindow(aWindow);    /* close this window */
  617.     }
  618.     while (closed && (aWindow != nil));
  619.     gQuit = true;
  620. } /*Terminate*/
  621.  
  622.  
  623. OSErr OpenOneWindow()
  624. {
  625.     WindowPtr    window;
  626.     Handle        data;
  627.  
  628.     window = (WindowPtr) NewPtr(sizeof(WindowRecord));
  629.     if ( window == nil )  {
  630.         DisplayError(0, nil, "Couldn't get a window record.");
  631.         return(memFullErr);
  632.     }
  633.  
  634.     window = GetNewWindow(rWindow, (Ptr) window, (WindowPtr) -1);
  635.     if ( window == nil ) {
  636.         DisplayError(0, nil, "Couldn't get a window from GetNewWindow.");
  637.         return(memFullErr);
  638.     }
  639.  
  640.     data = NewHandle(sizeof(WindowData));
  641.     if ( data == nil ) {
  642.         DisplayError(0, nil, "Couldn't get a window data handle.");
  643.         return(memFullErr);
  644.     }
  645.  
  646.     ((WindowPeek) window)->refCon = data;
  647.     InstallGlobalWindowData(window);
  648.  
  649.     ShowWindow(window);
  650.     SetPort(window);
  651.  
  652.     return(noErr);
  653. }
  654.  
  655. OSErr OpenNewWindow()
  656. {
  657.     SetInitialWindowState();
  658.     return(OpenOneWindow());
  659. }
  660.  
  661. void InstallGlobalWindowData(WindowPtr window)
  662. {
  663.     Handle    wData;
  664.  
  665.     if (window) {
  666.         wData = (Handle) ((WindowPeek) window)->refCon;
  667.         BlockMove((Ptr) &gWindowData, *wData, sizeof(WindowData));
  668.         SetWTitle(window, gTitle);
  669.     }
  670. }
  671.  
  672. void ExtractWindowData(WindowPtr window)
  673. {
  674.     Handle    wData;
  675.  
  676.     if (window) {
  677.         wData = (Handle) ((WindowPeek) window)->refCon;
  678.         BlockMove(*wData, (Ptr) &gWindowData, sizeof(WindowData));
  679.     }
  680. }
  681.  
  682. void SetInitialWindowState(void)
  683. {
  684.     gWindowData.stopped = true;
  685.     GetIndString(gTitle, kMiscStrings, korigName);    /* set default window title to untitled */
  686. }
  687.  
  688. /*    1.01 - The code that used to be part of ForceEnvirons has been moved into
  689.     this module. If an error is detected, instead of merely doing an ExitToShell,
  690.     which leaves the user without much to go on, we call AlertUser, which puts
  691.     up a simple alert that just says an error occurred and then calls ExitToShell.
  692.     Since there is no other cleanup needed at this point if an error is detected,
  693.     this form of error- handling is acceptable. If more sophisticated error recovery
  694.     is needed, an exception mechanism, such as is provided by Signals, can be used. */
  695.  
  696. #pragma segment Initialize
  697. void Initialize()
  698. {
  699.     Handle        menuBar;
  700.     long        total, contig;
  701.     EventRecord event;
  702.     short        count;
  703.     
  704.     InitGraf((Ptr) &qd.thePort);
  705.     InitFonts();
  706.     InitWindows();
  707.     InitMenus();
  708.     TEInit();
  709.     InitDialogs(nil);
  710.     InitCursor();
  711.  
  712.     for (count = 1; count <= 3; count++)
  713.         EventAvail(everyEvent, &event);
  714.  
  715.  
  716.     SysEnvirons(kSysEnvironsVersion, &gMac);
  717.  
  718.     if (gMac.machineType < 0) {
  719.         DisplayError(0, nil, "Need a Mac Plus or better.");
  720.         ExitToShell();
  721.     }
  722.  
  723.     if (gMac.systemVersion < 0x0600) {
  724.         DisplayError(0, nil, "Need System 6.0 or better.");
  725.         ExitToShell();
  726.     }
  727.  
  728.     gHasWaitNextEvent = TrapAvailable(_WaitNextEvent, ToolTrap);
  729.     gHasNewStdFile = (gMac.systemVersion >= 0x0700);
  730.  
  731.     if ((long) GetApplLimit() - (long) ApplicZone() < kMinHeap) {
  732.         DisplayError(0, nil, "Can't get enough heap space.");
  733.         ExitToShell();
  734.     }
  735.  
  736.     /* ZeroScrap(); */
  737.  
  738.     PurgeSpace(&total, &contig);
  739.     if (total < kMinSpace) {
  740.         DisplayError(0, nil, "Can't get enough free space.");
  741.         ExitToShell();
  742.     }
  743.  
  744.     InitAppleEvents();
  745.  
  746.     if ( !GoGetRect(rStopRect, &gStopRect) ) {
  747.         DisplayError(0, nil, "Couldn't get Stop rect.");
  748.         ExitToShell();
  749.     }
  750.     if ( !GoGetRect(rGoRect, &gGoRect) ) {
  751.         DisplayError(0, nil, "Couldn't get Go rect.");
  752.         ExitToShell();
  753.     }
  754.  
  755.     
  756. } /*Initialize*/
  757.  
  758.  
  759. void StartDocuments()
  760. {
  761.     OSErr        err = noErr;
  762.     short        i;
  763.     short        whatToDo;
  764.     short        numberOfFiles;
  765.     AppFile        theAppFile;
  766.     FSSpec        fileSpec;
  767.     long        ignoredProcID;
  768.     
  769.     if (!gHasAppleEvents) {
  770.         CountAppFiles(&whatToDo, &numberOfFiles);
  771.         if (numberOfFiles > 0) {
  772.             if (whatToDo == appPrint)
  773.                 PresentStyleDialog();
  774.             for (i = 1; i <= numberOfFiles && !err; ++i) {
  775.                 GetAppFiles(i, &theAppFile);
  776.                 ClrAppFiles(i);
  777.                 err = GetWDInfo(theAppFile.vRefNum,
  778.                                 &fileSpec.vRefNum,
  779.                                 &fileSpec.parID,
  780.                                 &ignoredProcID);
  781.                 if (err)
  782.                     DisplayError(err, nil, "StartDocuments: after GetWDInfo");
  783.                 else {
  784.                     BlockMove((Ptr) &theAppFile.fName, (Ptr) &fileSpec.name, theAppFile.fName[0] + 1);
  785.                     if (whatToDo == appOpen)
  786.                         err = OpenFile(&fileSpec);
  787.                     else if (whatToDo == appPrint)
  788.                         err = PrintFile(&fileSpec);
  789.                     else
  790.                         DisplayError(whatToDo, nil, "StartDocuments: got message from CountAppFiles I don't know what to do with.");
  791.                 } /* if (err) */
  792.             } /* for... */
  793.             if (whatToDo == appPrint)
  794.                 Terminate();
  795.         } /* if (numberOfFiles) */
  796.         else {
  797.             err = OpenNewWindow();
  798.         }
  799.     }
  800. }
  801.  
  802. /*    This utility loads the global rectangles that are used by the window
  803.     drawing routines. It shows how the resource manager can be used to hold
  804.     values in a convenient manner. These values are then easily altered without
  805.     having to re-compile the source code. In this particular case, we know
  806.     that this routine is being called at initialization time. Therefore,
  807.     if a failure occurs here, we will assume that the application is in such
  808.     bad shape that we should just exit. Your error handling may differ, but
  809.     the check should still be made. */
  810.  
  811. #pragma segment Initialize
  812. Boolean GoGetRect( short rectID, Rect *theRect )
  813. {
  814.     Handle        resource;
  815.  
  816.     resource = GetResource('RECT', rectID);
  817.     if ( resource != nil ) {
  818.         *theRect = **((Rect**) resource);
  819.         return true;
  820.     }
  821.     else
  822.         return false;
  823. } /* GoGetRect */
  824.  
  825.  
  826. #pragma segment Main
  827. Boolean IsAppWindow( WindowPtr window )
  828. {
  829.     short        windowKind;
  830.  
  831.     if ( window == nil )
  832.         return false;
  833.     else {    /* application windows have windowKinds = userKind (8) */
  834.         windowKind = ((WindowPeek) window)->windowKind;
  835.         return (windowKind = userKind);
  836.     }
  837. } /*IsAppWindow*/
  838.  
  839.  
  840. /* Check to see if a window belongs to a desk accessory. */
  841.  
  842. #pragma segment Main
  843. Boolean IsDAWindow( WindowPtr window )
  844. {
  845.     if ( window == nil )
  846.         return false;
  847.     else    /* DA windows have negative windowKinds */
  848.         return ((WindowPeek) window)->windowKind < 0;
  849. } /*IsDAWindow*/
  850.  
  851.  
  852. /*    Check to see if a given trap is implemented. This is only used by the
  853.     Initialize routine in this program, so we put it in the Initialize segment.
  854.     The recommended approach to see if a trap is implemented is to see if
  855.     the address of the trap routine is the same as the address of the
  856.     Unimplemented trap. */
  857. /*    1.02 - Needs to be called after call to SysEnvirons so that it can check
  858.     if a ToolTrap is out of range of a pre-MacII ROM. */
  859.  
  860. #pragma segment Initialize
  861. Boolean TrapAvailable( short tNumber, TrapType tType )
  862. {
  863.     if ( ( tType == ToolTrap ) &&
  864.         ( gMac.machineType > envMachUnknown ) &&
  865.         ( gMac.machineType < envMacII ) ) {        /* it's a 512KE, Plus, or SE */
  866.         tNumber = tNumber & 0x03FF;
  867.         if ( tNumber > 0x01FF )                    /* which means the tool traps */
  868.             tNumber = _Unimplemented;            /* only go to 0x01FF */
  869.     }
  870.     return NGetTrapAddress(tNumber, tType) != GetTrapAddress(_Unimplemented);
  871. } /*TrapAvailable*/
  872.  
  873.  
  874. /*    Display an alert that tells the user an error occurred, then exit the program.
  875.     This routine is used as an ultimate bail-out for serious errors that prohibit
  876.     the continuation of the application. Errors that do not require the termination
  877.     of the application should be handled in a different manner. Error checking and
  878.     reporting has a place even in the simplest application. The error number is used
  879.     to index an 'STR#' resource so that a relevant message can be displayed. */
  880.  
  881. #pragma segment Main
  882. void AlertUser()
  883. {
  884.     short        itemHit;
  885.  
  886.     SetCursor(&qd.arrow);
  887.     itemHit = Alert(rUserAlert, nil);
  888.     ExitToShell();
  889. } /* AlertUser */
  890.  
  891.  
  892.  
  893.  
  894.  
  895.  
  896.  
  897.  
  898.  
  899.